/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.meteocal_pappalardo_sacchi.bean;

import it.polimi.meteocal_pappalardo_sacchi.entity.Event;
import it.polimi.meteocal_pappalardo_sacchi.entity.MeteoCalUser;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;

/**
 *
 *
 */
@Stateless
public class EventManager extends AbstractManager<Event> {
    @PersistenceContext(unitName = "authPU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public EventManager() {
        super(Event.class);
    }

    /**
     * 
     * @param event
     * @return a list with users who have been invited to the @event
     */
    public List<MeteoCalUser> findAlreadyInvitedUserList(Event event) {
           
        String queryString = "SELECT u " +
                            "FROM CALENDAR c JOIN METEOCAL_USER u " +
                            "WHERE :event = c.joinedEventList " +
                            "AND c.owner = u";

        Query query = em.createQuery(queryString);        
        query.setParameter("event", event);
        return query.getResultList();
        
    }

    /**
     * query to be run by the scheduler each day at midnight
     * @return a list with events starting the following day with unfavorable forecast
     */
    public List<Event> findEventsStartingIn24HoursWithBadWeather() {        
        java.sql.Date tomorrow = java.sql.Date.valueOf(LocalDate.now(ZoneId.of("Europe/Paris")).plusDays(1));
        
        String queryString = "SELECT e " +
                             "FROM EVENT e JOIN WF w " +	
                             "WHERE w= e.weatherForecastList " +
                             "AND e.outdoor = TRUE "+
                             "AND e.startingDate = :tomorrow " +
                             "AND ((e.weatherCondition.rain = TRUE AND w.weatherCondition.rain = TRUE) " +
                             "OR (e.weatherCondition.snow = TRUE AND w.weatherCondition.snow = TRUE) " + 
                             "OR (e.weatherCondition.cloud = TRUE AND w.weatherCondition.cloud = TRUE) " +
                             "OR (e.weatherCondition.temperature > w.weatherCondition.temperature) " +
                             "OR (e.weatherCondition.windStrength < w.weatherCondition.windStrength))"; 
        
        Query query = em.createQuery(queryString);        
        query.setParameter("tomorrow", tomorrow);
        return query.getResultList();
    }

    /**
     *
     * @return a list of outdoor events starting from tomorrow onwards
     */
    public List<Event> findOutdoorEventsStartingFromTomorrowTo15Days() {
        java.sql.Date today = java.sql.Date.valueOf(LocalDate.now(ZoneId.of("Europe/Paris")));
        java.sql.Date fifteenDays = java.sql.Date.valueOf(LocalDate.now(ZoneId.of("Europe/Paris")).plusDays(15));


        String queryString = "SELECT e " +
                "FROM EVENT e " +
                "WHERE e.outdoor = TRUE "+
                "AND e.startingDate > :today " +
                "AND e.startingDate < :fifteenDays";

        Query query = em.createQuery(queryString);
        query.setParameter("today", today);
        query.setParameter("fifteenDays", fifteenDays);
        return query.getResultList();
    }
    
    /**
     * 
     * @return the list of  outdoor events with unfavorable weather forecast starting in three days
     */
    public List<Event> findEventsWithBadWeatherStartingIn3Days() {
        java.sql.Date threeDays = java.sql.Date.valueOf(LocalDate.now(ZoneId.of("Europe/Paris")).plusDays(3));
        
        String queryString = "SELECT DISTINCT e " +
                             "FROM EVENT e JOIN WF w " +	
                             "WHERE w= e.weatherForecastList " +
                             "AND e.outdoor = TRUE "+
                             "AND (e.startingDate = :threeDays) " +
                             "AND ((e.weatherCondition.rain = TRUE AND w.weatherCondition.rain = TRUE) " +
                             "OR (e.weatherCondition.snow = TRUE AND w.weatherCondition.snow = TRUE) " + 
                             "OR (e.weatherCondition.cloud = TRUE AND w.weatherCondition.cloud = TRUE) " +
                             "OR (e.weatherCondition.temperature > w.weatherCondition.temperature) " +
                             "OR (e.weatherCondition.windStrength < w.weatherCondition.windStrength))"; 
        
        Query query = em.createQuery(queryString);        
        query.setParameter("threeDays", threeDays);
        return query.getResultList();               
    }

    public MeteoCalUser findCreator(Event event) {        
        String queryString = "SELECT u " +
                             "FROM METEOCAL_USER u " +	
                             "WHERE u = :creator"; 
        
        Query query = em.createQuery(queryString);        
        query.setParameter("creator", event.getCreator());
        
        return (MeteoCalUser) query.getSingleResult();
    }

    public List<MeteoCalUser> findJoinedUserListByEvent(Event event) {
        String queryString = "SELECT DISTINCT c.owner " +
                "FROM EVENT e JOIN CALENDAR c JOIN Invitation i " +
                "WHERE e = :event " +
                "AND c = e.participantCalendarList " +
                "AND ((i.sentToUser = c.owner AND i.relatedEvent = e AND i.doesParticipate = true) " +
                "OR (e.creator = c.owner))";

        Query query = em.createQuery(queryString);
        query.setParameter("event", event);
        return query.getResultList();
    }

    /**
     * 
     * @param event
     * @return true if the event is starting today or tomorrow
     */
    public boolean isEventStartingTodayOrTomorrow(Event event) {
        //prendo data odierna per il fuso italiano
        ZoneId zone = ZoneId.of("Europe/Paris");
        LocalDate today = LocalDate.now(zone);
        return event.getStartingDate().toLocalDate().isEqual(today) || event.getStartingDate().toLocalDate().isEqual(today.plusDays(1));
    }

    public List<Event> findAllOutdoorOngoingEvents() {
        java.sql.Date today = java.sql.Date.valueOf(LocalDate.now(ZoneId.of("Europe/Paris")));

        String queryString = "SELECT e " +
                "FROM EVENT e " +
                "WHERE e.outdoor = TRUE "+
                "AND e.startingDate < :today AND e.endingDate > :today";

        Query query = em.createQuery(queryString);
        query.setParameter("today", today);
        return query.getResultList();
    }
}
